package com.adam.example.search.converter;

import co.elastic.clients.elasticsearch._types.DistanceUnit;
import com.fasterxml.jackson.databind.util.StdConverter;
import org.elasticsearch.geometry.*;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

//参考Deepseek
public class MapToGeometryConverter extends StdConverter<Map<String, Object>, Geometry> {

    @Override
    public Geometry convert(Map<String, Object> value) {
//        System.out.println(value);
        String type = ((String) value.get("type")).toLowerCase();

        return switch (type) {
            case "point" -> createPoint((List<Double>) value.get("coordinates"));
            case "linestring" -> createLineString((List<List<Double>>) value.get("coordinates"));
            case "polygon" -> createPolygon((List<List<List<Double>>>) value.get("coordinates"));
            case "multipoint" -> createMultiPoint((List<List<Double>>) value.get("coordinates"));
            case "multilinestring" -> createMultiLineString((List<List<List<Double>>>) value.get("coordinates"));
            case "multipolygon" -> createMultiPolygon((List<List<List<List<Double>>>>) value.get("coordinates"));
            case "geometrycollection" -> createGeometryCollection((List<Map<String, Object>>) value.get("geometries"));
            case "envelope" -> createEnvelope((List<Object>) value.get("coordinates"));
            case "circle" -> createCircle(value);
            default -> throw new IllegalArgumentException("Unsupported geo_shape type: " + type);
        };
    }

    private Point createPoint(List<Double> coords) {
        return new Point(coords.get(0), coords.get(1));
    }

    private Line createLineString(List<List<Double>> coordsList) {
        double[] lats = new double[coordsList.size()];
        double[] lons = new double[coordsList.size()];

        for (int i = 0; i < coordsList.size(); i++) {
            List<Double> coord = coordsList.get(i);
            lons[i] = coord.get(0);
            lats[i] = coord.get(1);
        }
        return new Line(lons, lats);
    }

    private Polygon createPolygon(List<List<List<Double>>> rings) {
        // 创建外环
        LinearRing shell = createLinearRing(rings.get(0));

        // 创建内环（孔洞）
        LinearRing[] holes = new LinearRing[rings.size() - 1];
        for (int i = 1; i < rings.size(); i++) {
            holes[i - 1] = createLinearRing(rings.get(i));
        }

        return new Polygon(shell, List.of(holes));
    }

    private LinearRing createLinearRing(List<List<Double>> coordsList) {
        double[] lats = new double[coordsList.size()];
        double[] lons = new double[coordsList.size()];

        for (int i = 0; i < coordsList.size(); i++) {
            List<Double> coord = coordsList.get(i);
            lons[i] = coord.get(0);
            lats[i] = coord.get(1);
        }
        return new LinearRing(lons, lats);
    }

    private MultiPoint createMultiPoint(List<List<Double>> points) {
        List<Point> pointList = new LinkedList<>();
        for(List<Double> coordinate: points) {
            Point point = createPoint(coordinate);
            pointList.add(point);
        }
        return new MultiPoint(pointList);
    }

    private MultiLine createMultiLineString(List<List<List<Double>>> lines) {
        Line[] lineArray = new Line[lines.size()];
        for (int i = 0; i < lines.size(); i++) {
            lineArray[i] = createLineString(lines.get(i));
        }
        return new MultiLine(List.of(lineArray));
    }

    private MultiPolygon createMultiPolygon(List<List<List<List<Double>>>> polygons) {
        Polygon[] polygonArray = new Polygon[polygons.size()];
        for (int i = 0; i < polygons.size(); i++) {
            polygonArray[i] = createPolygon(polygons.get(i));
        }
        return new MultiPolygon(List.of(polygonArray));
    }

    private GeometryCollection<Geometry> createGeometryCollection(List<Map<String, Object>> geometries) {
        Geometry[] shapes = new Geometry[geometries.size()];
        for (int i = 0; i < geometries.size(); i++) {
            shapes[i] = convert(geometries.get(i));
        }
        return new GeometryCollection<>(List.of(shapes));
    }

    private Rectangle createEnvelope(List<Object> coords) {
        // 信封格式: [[minLon, maxLat], [maxLon, minLat]]
        if (coords.size() == 2 && coords.get(0) instanceof List) {
            // 处理嵌套列表格式
            List<Double> topLeft = (List<Double>) coords.get(0);
            List<Double> bottomRight = (List<Double>) coords.get(1);
            return new Rectangle(topLeft.get(0), bottomRight.get(0), bottomRight.get(1), topLeft.get(1));
        } else if (coords.size() == 4) {
            // 处理扁平化格式 [minLon, maxLon, maxLat, minLat]
            List<Double> coordDoubles = coords.stream().map(object -> Double.parseDouble(object.toString())).toList();
            return new Rectangle(coordDoubles.get(0), coordDoubles.get(1), coordDoubles.get(3), coordDoubles.get(2));
        }
        throw new IllegalArgumentException("Invalid envelope coordinates format");
    }

    private Circle createCircle(Map<String, Object> value) {
        List<Double> center = (List<Double>) value.get("coordinates");
        String radiusStr = (String) value.get("radius");

        // 解析半径值（示例格式："100m"）
        double radius = parseRadius(radiusStr);
        return new Circle(center.get(0), center.get(1), radius);
    }

    private double parseRadius(String radiusStr) {
        String metersUnit = DistanceUnit.Meters.jsonValue(),
                kilometersUnit = DistanceUnit.Kilometers.jsonValue();
        // 简化的半径解析逻辑（实际实现可能需要更完整的单位转换）
        if (radiusStr.endsWith(metersUnit)) {
            return Double.parseDouble(radiusStr.substring(0, radiusStr.length() - metersUnit.length()));
        } else if(radiusStr.endsWith(kilometersUnit)) {
            return Double.parseDouble(radiusStr.substring(0, radiusStr.length() - kilometersUnit.length()));
        }
        throw new IllegalArgumentException("Unsupported radius unit: " + radiusStr);
    }
}